home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 46 / Amiga Format CD46 (1999-10-20)(Future Publishing)(GB)[!][issue 1999-12].iso / -serious- / comms / www / urlx / urlx.c < prev    next >
C/C++ Source or Header  |  1999-09-06  |  11KB  |  563 lines

  1. /*
  2.  *  program to extract URL's from any file
  3.  */
  4.  
  5. #include <sys/types.h>
  6.  
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <ctype.h>
  11. #include <errno.h>
  12.  
  13. #include "ubi_BinTree.h"
  14.  
  15. typedef struct
  16. {
  17.   ubi_trNode Node;
  18.   char       Name[0];
  19. } NameRec;
  20.  
  21. static ubi_trRoot Root;
  22.  
  23. FILE   *f1_p;
  24. FILE   *f2_p;
  25.  
  26. #define BUFSIZE 65536
  27.  
  28. static const char PROGVER[] =
  29.   "\0$VER: urlx V1.00 ** (c) Aug 99 ** frans";
  30.  
  31. static const char USAGE[] =
  32.   "usage: urlx [options] <infile> [outfile]\n\n"
  33.   "options:\n"
  34.   "  -h      output as html file\n"
  35.   "  -s      sort output\n"
  36.   "  -u      special url sorted output\n"
  37.   "  -p      keep parameters after url's\n"
  38.   "  -d      allow duplicate url's\n"
  39.   "  -a      allow accented characters\n"
  40.   "  -.<ext> output only matching extension(s)\n"
  41.   "  -i      output only .html etc entries\n"
  42.   "\n"
  43.   "  <infile> can be - to indicate stdin";
  44.  
  45. void shutdown(char *msg, ...)
  46. {
  47.   vfprintf(stderr, msg, (void *)(&msg + 1));
  48.   exit(0);
  49. }
  50.  
  51. void usage(void)
  52. {
  53.   shutdown("%s\n\n%s\n\n", PROGVER + 7, USAGE);
  54. }
  55.  
  56. typedef struct memChunk
  57. {
  58.   struct memChunk *next;
  59.   u_char data[0];
  60. } memChunk;
  61.  
  62. memChunk *xmc = 0;
  63.  
  64. void *xmalloc(long len)
  65. {
  66.   memChunk *mc;
  67.  
  68.   if ((mc = (memChunk *)malloc(sizeof(memChunk) + len)) == 0)
  69.     shutdown("out of memory\n");
  70.  
  71.   mc->next = xmc;
  72.   xmc = mc;
  73.  
  74.   return ((void *)mc->data);
  75. }
  76.  
  77. void xfree(void *mem)
  78. {
  79.   memChunk *mc, *this, *prev, *next;
  80.  
  81.   if (mem)
  82.     mc = (memChunk *)((char *)mem - sizeof(memChunk));
  83.   else
  84.     mc = 0;
  85.  
  86.   for (this = xmc, prev = 0; this != 0; this = next)
  87.   {
  88.     next = this->next;
  89.  
  90.     if (mc == 0 || mc == this)
  91.     {
  92.       if (prev)
  93.         prev->next = next;
  94.       else
  95.         xmc = next;
  96.  
  97.       free(this);
  98.  
  99.       if (mc)
  100.         break;
  101.     }
  102.     else
  103.       prev = this;
  104.   }
  105. }
  106.  
  107. void cleanup(void)
  108. {
  109.   if (f1_p && f1_p != stdin)
  110.     fclose(f1_p);
  111.  
  112.   if (f2_p && f2_p != stdout)
  113.     fclose(f2_p);
  114.  
  115.   xfree(0);
  116. }
  117.  
  118. /*---------------------------------------------------------------
  119.  *  btree stuff
  120.  */
  121. int str_compare(char *s1, int s1len, char *s2, int s2len)
  122. {
  123.   int result = strnicmp(s1, s2, (s1len < s2len)? s1len : s2len);
  124.  
  125.   if (result == 0)
  126.   {
  127.     if (s1len > s2len)
  128.       return (1);
  129.     else if (s2len > s1len)
  130.       return (-1);
  131.   }
  132.  
  133.   return (result);
  134. }
  135.  
  136. static int CompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr)
  137. {
  138.   char *Name     = (char *)ItemPtr;
  139.   char *NodeName = ((NameRec *)NodePtr)->Name;
  140.  
  141.   return (stricmp(Name, NodeName));
  142. }
  143.  
  144. int get_first_bit(char *p, char **pp, int *pplen)
  145. {
  146.   char *p0, *p1;
  147.   int  p1len;
  148.  
  149.   for (p0 = p, p1 = 0, p1len = 0; *p != 0; p++)
  150.   {
  151.     if (*p == ':' && p1 == 0)
  152.     {
  153.       p += 2; p1 = p + 1; p1len = p1 - p0;
  154.     }
  155.     else if (*p == '/' && p1 != 0)
  156.     {
  157.       break;
  158.     }
  159.   }
  160.  
  161.   if (p1len)
  162.   {
  163.     *pp    = p1;
  164.     *pplen = p - p1;
  165.   }
  166.  
  167.   return (p1len);
  168. }
  169.  
  170. int get_last_bit(char *p, int plen, char **pp)
  171. {
  172.   char *p0, *p1;
  173.  
  174.   for (p0 = p, p1 = p; p - p0 < plen; p++)
  175.   {
  176.     if (*p == '.')
  177.     {
  178.       p1 = p + 1;
  179.     }
  180.   }
  181.  
  182.   *pp = p1;
  183.  
  184.   return (plen - (p1 - p0));
  185. }
  186.  
  187. /*
  188.  *  special url order
  189.  */
  190. static int URLCompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr)
  191. {
  192.   char *Name     = (char *)ItemPtr;
  193.   char *NodeName = ((NameRec *)NodePtr)->Name;
  194.   int  result;
  195.   char *p1, *p2;
  196.   int  p1len, p2len;
  197.   char *s1, *s2;
  198.   int  s1len, s2len;
  199.  
  200.   s1len = get_first_bit(Name, &p1, &p1len);
  201.   s2len = get_first_bit(NodeName, &p2, &p2len);
  202.  
  203.   if (   s1len != s2len
  204.       || strnicmp(Name, NodeName, s1len) != 0)
  205.     return str_compare(Name, strlen(Name), NodeName, strlen(NodeName));
  206.  
  207.   for (;;)
  208.   {
  209.     s1len = get_last_bit(p1, p1len, &s1);
  210.     s2len = get_last_bit(p2, p2len, &s2);
  211.  
  212.     if (result = str_compare(s1, s1len, s2, s2len))
  213.       return (result);
  214.  
  215.     if (s1len >= p1len || s2len >= p2len)
  216.       break;
  217.  
  218.     p1len -= (s1len + 1);
  219.     p2len -= (s2len + 1);
  220.   }
  221.  
  222.   return str_compare(Name, strlen(Name), NodeName, strlen(NodeName));
  223. }
  224.  
  225. static void KillNode(ubi_trNodePtr NodePtr)
  226. {
  227.   free(NodePtr);
  228. }
  229.  
  230. int fillbuf(u_char *buf, int buflen, char *data, int datalen)
  231. {
  232.   if (datalen)
  233.     memcpy(buf, data, datalen);
  234.  
  235.   datalen += fread(buf + datalen, 1, buflen - datalen, f1_p);
  236.  
  237.   return (datalen);
  238. }
  239.  
  240. int main(int argc, char **argv)
  241. {
  242.   int     i, quiet_f, verbose_f;
  243.   int     param_ok_f, html_f, index_f, space_ok_f, sort_f, dup_ok_f, accent_ok_f;
  244.   long    datalen;
  245.   FILE    *f_out;
  246.   char    *f1_name, *f2_name;
  247.   u_char  *p;
  248.   char    ext1[40], ext2[40];
  249.   u_char  *buf;
  250.   int     valid;
  251.  
  252.   f1_p     = f2_p    = 0;
  253.   f1_name  = f2_name = 0;
  254.   buf      = 0;
  255.  
  256.   memset(&Root, 0, sizeof(ubi_trRoot));
  257.  
  258.   quiet_f  = verbose_f = 0;
  259.   param_ok_f = html_f = index_f = space_ok_f = sort_f = dup_ok_f = accent_ok_f = 0;
  260.  
  261.   ext1[0] = ext2[0] = 0;
  262.  
  263.   atexit(cleanup);
  264.  
  265.   for (i = 1; i < argc; i++)
  266.   {
  267.     if (verbose_f)
  268.       fprintf(stderr, "%s\n", argv[i]);
  269.  
  270.     if (*(p = argv[i]) == '-')
  271.     {
  272.       switch (*++p)
  273.       {
  274.       case 'v':
  275.         verbose_f = 1;
  276.         if (*++p == 'v')
  277.           verbose_f = 2;
  278.         break;
  279.       case 'q':
  280.         quiet_f = 1;
  281.         if (*++p == 'q')
  282.           quiet_f = 2;
  283.         break;
  284.       case 'p':
  285.         param_ok_f = 1;
  286.         break;
  287.       case 'a':
  288.         accent_ok_f = 1;
  289.         break;
  290.       case 'w': /* allow white space in urls */
  291.         space_ok_f = 1;
  292.         break;
  293.       case 'i':
  294.         index_f = 1;
  295.         strcpy(ext1, "htm");
  296.         strcpy(ext2, "shtm");
  297.         break;
  298.       case 'h':
  299.         html_f = 1;
  300.         break;
  301.       case 's':
  302.         sort_f = 1;
  303.         break;
  304.       case 'u':
  305.         sort_f = 2;
  306.         break;
  307.       case 'd':
  308.         dup_ok_f = 1;
  309.         break;
  310.       case '.':
  311.         if (ext1[0] == 0)
  312.           strcpy(ext1, ++p);
  313.         else if (ext2[0] == 0)
  314.           strcpy(ext2, ++p);
  315.         else
  316.           usage();
  317.         break;
  318.       case 0:
  319.         if (!f1_p)
  320.         {
  321.           f1_p = stdin;
  322.           break;
  323.         }
  324.       default:
  325.         usage();
  326.       }
  327.     }
  328.     else if (f1_p == 0 && f1_name == 0)
  329.       f1_name = p;
  330.     else if (f2_name == 0)
  331.       f2_name = p;
  332.     else
  333.       usage();
  334.   }
  335.   if (f1_p == 0 && f1_name == 0)
  336.     usage();
  337.  
  338.   if (verbose_f)
  339.     printf("%s\n\n", PROGVER + 7);
  340.  
  341.   if (f1_p == 0 && (f1_p = fopen(f1_name, "rb")) == 0)
  342.     shutdown("Couldn't open input file %s\n", f1_name);
  343.  
  344.   if (f2_name && (f2_p = fopen(f2_name, "wb")) == 0)
  345.     shutdown("Couldn't open output file %s\n", f2_name);
  346.  
  347.   if (f2_p)
  348.     f_out = f2_p;
  349.   else
  350.     f_out = stdout;
  351.  
  352.   ubi_trInitTree(&Root,
  353.                  (sort_f == 2)? URLCompareFunc : CompareFunc,
  354.                  0);          /* Don't allow overwrites or duplicates */
  355.  
  356.   buf = xmalloc(BUFSIZE);
  357.  
  358.   /*
  359.    *  read file into buffer and scan
  360.    */
  361.   for (p = buf, datalen = 0, valid = 0; ; )
  362.   {
  363.     u_char *url, *lastdot;
  364.     int    i_f, plen;
  365.  
  366.     if (valid == -1 || (p - buf) + 8 >= datalen)
  367.     {
  368.       if (datalen && datalen < BUFSIZE)
  369.         break;
  370.  
  371.       if (datalen && p - buf < datalen)
  372.         datalen = fillbuf(buf, BUFSIZE, p, datalen - (p - buf));
  373.       else
  374.         datalen = fillbuf(buf, BUFSIZE, 0, 0);
  375.  
  376.       if (verbose_f)
  377.         fprintf(stderr, " filled buffer %ld\n", datalen);
  378.  
  379.       if (datalen == 0)
  380.         break;
  381.  
  382.       p = buf;
  383.     }
  384.  
  385.     url = p;
  386.  
  387.     switch (*p)
  388.     {
  389.     case 'h': case 'H':
  390.       if (strnicmp(p, "http://", 7) == 0)
  391.         plen = 7;
  392.       else if (strnicmp(p, "https://", 8) == 0)
  393.         plen = 8;
  394.       else
  395.       {
  396.         p++;
  397.         continue;
  398.       }
  399.       break;
  400.     case 'f': case 'F':
  401.       if (strnicmp(p, "ftp://", 6) == 0)
  402.         plen = 6;
  403.       else
  404.       {
  405.         p++;
  406.         continue;
  407.       }
  408.       break;
  409.     default:
  410.       p++;
  411.       continue;
  412.     }
  413.  
  414.     p += plen;
  415.  
  416.     for (valid = 0, lastdot = 0, i_f = -1; ; )
  417.     {
  418.       if (p - buf >= datalen)
  419.       {
  420.         valid = -1;
  421.         break;
  422.       }
  423.  
  424.       if (*p < 32 || (!accent_ok_f && *p > 127))
  425.       {
  426.         if (*p == 0 || *p == 0x0A || *p == 0x0D)
  427.           valid = 1;
  428.         break;
  429.       }
  430.       else if (   *p == '\"' || *p == '\''
  431.                || *p == '>'  || *p == '<'
  432.                || (!space_ok_f && *p == ' ')
  433.                || (!param_ok_f && (*p == '?' || *p == '#')))
  434.       {
  435.         valid = 1;
  436.         break;
  437.       }
  438.       else if (*p == '.')
  439.         lastdot = p;
  440.       else if (*p == '/')
  441.         i_f = 1;
  442.       else if (i_f != -1)
  443.         i_f = 0;
  444.  
  445.       p++;
  446.     }
  447.  
  448.     if (!valid)
  449.     {
  450.       p = url + 1;
  451.       continue;
  452.     }
  453.     else if (valid == -1)
  454.     {
  455.       p = url;
  456.       continue;
  457.     }
  458.  
  459.     if (   (ext1[0] == 0 && ext2[0] == 0)
  460.         || (lastdot != 0 && ext1[0] != 0 && strnicmp(lastdot + 1, ext1, strlen(ext1)) == 0)
  461.         || (lastdot != 0 && ext2[0] != 0 && strnicmp(lastdot + 1, ext2, strlen(ext2)) == 0)
  462.         || index_f && i_f != 0)
  463.     {
  464.       /*
  465.        *  if name already in table continue,
  466.        *  else add name to table...
  467.        */
  468.       NameRec *RecPtr, *OldRecPtr;
  469.       int     urllen = p - url;
  470.  
  471.       if (!(RecPtr = (NameRec *)malloc(sizeof(NameRec)+urllen+1)))
  472.         shutdown("out of memory\n");
  473.  
  474.       strncpy(RecPtr->Name, url, urllen);
  475.       RecPtr->Name[urllen] = 0;
  476.  
  477.       if (!ubi_trInsert(&Root,
  478.                         RecPtr,
  479.                         RecPtr->Name,
  480.                         &OldRecPtr)
  481.          )
  482.       {
  483.         /*
  484.          *  name already in table
  485.          */
  486.         free(RecPtr);
  487.  
  488.         if (!dup_ok_f)
  489.           continue;
  490.  
  491.         RecPtr = OldRecPtr;
  492.       }
  493.  
  494.       if (sort_f)
  495.         continue;
  496.  
  497.       if (html_f > 0)
  498.       {
  499.         fprintf(f_out, "<HTML><TITLE>bookmarks</TITLE><BODY><UL>\n");
  500.         html_f = -1;
  501.       }
  502.  
  503.       if (html_f)
  504.       {
  505.         fprintf(f_out, "<LI><A HREF=\"%s\">%s</A>\n",
  506.                 RecPtr->Name, RecPtr->Name + plen);
  507.       }
  508.       else
  509.       {
  510.         fprintf(f_out, "%s\n", RecPtr->Name);
  511.       }
  512.     }
  513.   }
  514.  
  515.   if (sort_f)
  516.   {
  517.     NameRec *RecPtr;
  518.  
  519.     for (RecPtr  = (NameRec *)ubi_trFirst(Root.root);
  520.          RecPtr != 0;
  521.          RecPtr  = (NameRec *)ubi_trNext(RecPtr))
  522.     {
  523.       char *url;
  524.       int  plen;
  525.  
  526.       url = RecPtr->Name;
  527.  
  528.       if (html_f > 0)
  529.       {
  530.         fprintf(f_out, "<HTML><TITLE>bookmarks</TITLE><BODY><UL>\n");
  531.         html_f = -1;
  532.       }
  533.  
  534.       if (html_f)
  535.       {
  536.         if (strnicmp(url, "http://", 7) == 0)
  537.           plen = 7;
  538.         if (strnicmp(url, "https://", 8) == 0)
  539.           plen = 8;
  540.         else if (strnicmp(url, "ftp://", 6) == 0)
  541.           plen = 6;
  542.         else
  543.           plen = 0;
  544.  
  545.         fprintf(f_out, "<LI><A HREF=\"%s\">%s</A>\n", url, url + plen);
  546.       }
  547.       else
  548.       {
  549.         fprintf(f_out, "%s\n", url);
  550.       }
  551.     }
  552.   }
  553.  
  554.   if (html_f < 0)
  555.   {
  556.     fprintf(f_out, "</UL></BODY></HTML>\n");
  557.   }
  558.  
  559.   ubi_trKillTree(&Root, KillNode);
  560.  
  561.   exit(0);
  562. }
  563.